@node Records
@section Records

@cindex abstract data types
@cindex opaque data types
Scheme48 provides several different levels of a record facility.  Most
programmers will probably not care about the two lower levels; the
syntactic record type definers are sufficient for abstract data types.

@cindex defining record types
@cindex record types, defining
@stindex define-record-types
@stindex defrecord
@stindex srfi-9
At the highest level, there are two different record type definition
macros.  Richard Kelsey's is exported from the @code{defrecord}
structure; Jonathan Rees's is exported from @code{define-record-types}.
They both export a @code{define-record-type} macro and the same
@code{define-record-discloser} procedure; however, the macros are
dramatically different.  Scheme48 also provides [SRFI 9], which is
essentially Jonathan Rees's record type definition macro with a slight
syntactic difference, in the @code{srfi-9} structure.  Note, however,
that @code{srfi-9} does not export @code{define-record-discloser}.  The
difference between Jonathan Rees's and Richard Kelsey's record type
definition macros is merely syntactic convenience; Jonathan Rees's more
conveniently allows for arbitrary naming of the generated variables,
whereas Richard Kelsey's is more convenient if the naming scheme varies
little.

@subsection Jonathan Rees's @code{define-record-type} macro

@deffn syntax define-record-type
@lisp
(define-record-type @var{record-type-name} @var{record-type-variable}
  (@var{constructor} @var{constructor-argument} @dots{})
  [@var{predicate}]
  (@var{field-tag} @var{field-accessor} [@var{field-modifier}])
  @dots{})@end lisp
This defines @var{record-type-variable} to be a record type descriptor.
@var{Constructor} is defined to be a procedure that accepts the listed
field arguments and creates a record of the newly defined type with
those fields initialized to the corresponding arguments.
@var{Predicate}, if present, is defined to be the disjoint (as long as
abstraction is not violated by the lower-level record interface) type
predicate for the new record type.  Each @var{field-accessor} is
defined to be a unary procedure that accepts a record type and returns
the value of the field named by the corresponding @var{field-tag}.
Each @var{field-modifier}, if present, is defined to be a binary
procedure that accepts a record of the new type and a value, which it
assigns the field named by the corresponding @var{field-tag} to.  Every
@var{constructor-argument} must have a corresponding @var{field-tag},
though @var{field-tag}s that are not used as arguments to the record
type's constructor are simply uninitialized when created.  They should
have modifiers: otherwise they will never be initialized.

It is worth noting that Jonathan Rees's @code{define-record-type} macro
does not introduce identifiers that were not in the original macro's
input form.

For example:

@lisp
(define-record-type pare rtd/pare
  (kons a d)
  pare?
  (a kar) 
  (d kdr set-kdr!))

(kar (kons 5 3))
    @result{} 5

(let ((p (kons 'a 'c)))
  (set-kdr! p 'b)
  (kdr p))
    @result{} b

(pare? (kons 1 2))
    @result{} #t

(pare? (cons 1 2))
    @result{} #f@end lisp
@end deffn

There is also a variant of Jonathan Rees's @code{define-record-type}
macro for defining record types with fields whose accessors and
modifiers respect @embedref{Optimistic concurrency, optimistic
concurrency} by logging in the current proposal.

@subsection Richard Kelsey's @code{define-record-type} macro

@deffn syntax define-record-type
@lisp
(define-record-type @var{type-name}
  (@var{argument-field-specifier} @dots{})
  (@var{nonargument-field-specifier} @dots{}))

    @var{argument-field-specifier} @returns{}
        @var{field-tag}              Immutable field
      | (@var{field-tag})            Mutable field
    @var{nonargument-field-specifier} @returns{}
        @var{field-tag}              Uninitialized field
      | (@var{field-tag} @var{exp})        Initialized with @var{exp}'s value@end lisp
@c Huh?  --->                        ^^^^^^ -- oh, due to extra @var{}
This defines @code{type/@var{type-name}} to be a record type descriptor
for the newly defined record type, @code{@var{type-name}-maker} to be
a constructor for the new record type that accepts arguments for every
field in the argument field specifier list, @code{@var{type-name}?} to
be the disjoint type predicate for the new record type, accessors for
each field tag @var{field-tag} by constructing an identifier
@code{@var{type-name}-@var{field-tag}}, and modifiers for each argument
field tag that was specified to be mutable as well as each nonargument
field tag.  The name of the modifier for a field tag @var{field-tag} is
constructed to be
@code{set-@var{type-name}-@var{field-tag}!}.

Note that Richard Kelsey's @code{define-record-type} macro @emph{does}
concatenate & introduce new identifiers, unlike Jonathan Rees's.

For example, a use of Richard Kelsey's @code{define-record-type} macro

@lisp
(define-record-type pare
  (kar
   (kdr))
  (frob
   (mumble 5)))@end lisp

@noindent
is equivalent to the following use of Jonathan Rees's macro

@lisp
(define-record-type pare type/pare
  (%pare-maker kar kdr mumble)
  pare?
  (kar pare-kar)
  (kdr pare-kdr set-pare-kdr!)
  (frob pare-frob set-pare-frob!)
  (mumble pare-mumble set-pare-mumble!))

(define (pare-maker kar kdr)
  (%pare-maker kar kdr 5))@end lisp
@end deffn

@subsection Record types

@cindex programmatic record types
@cindex record types, programmatic
@stindex record-types
Along with two general record type definition facilities, there are
operations directly on the record type descriptors themselves, exported
by the @code{record-types} structure.  (Record type descriptors are
actually records themselves.)

@deffn procedure make-record-type name field-tags @returns{} record-type-descriptor
@deffnx procedure record-type? object @returns{} boolean
@code{Make-record-type} makes a record type descriptor with the given
name and field tags.  @code{Record-type?} is the disjoint type
predicate for record types.
@end deffn

@deffn procedure record-type-name rtype-descriptor @returns{} symbol
@deffnx procedure record-type-field-names rtype-descriptor @returns{} symbol-list
Accessors for the two record type descriptor fields.
@end deffn

@deffn procedure record-constructor rtype-descriptor argument-field-tags @returns{} constructor-procedure
@deffnx procedure record-predicate rtype-descriptor @returns{} predicate-procedure
@deffnx procedure record-accessor rtype-descriptor field-tag @returns{} accessor-procedure
@deffnx procedure record-modifier rtype-descriptor field-tag @returns{} modifier-procedure
Constructors for the various procedures relating to record types.
@code{Record-constructor} returns a procedure that accepts arguments
for each field in @var{argument-field-tags} and constructs a record
whose record type descriptor is @var{rtype-descriptor}, initialized
with its arguments.  @code{Record-predicate} returns a disjoint type
predicate for records whose record type descriptor is
@var{rtype-descriptor}.  @code{Record-accessor} and
@code{record-modifier} return accessors and modifiers for records
whose record type descriptor is @var{rtype-descriptor} for the given
fields.
@end deffn

@deffn procedure define-record-discloser rtype-descriptor discloser @returns{} unspecific
Defines the method by which records of type @var{rtype-descriptor} are
disclosed (@pxref{Writer}).  This is also exported by
@code{define-record-types} and @code{defrecord}.
@end deffn

@deffn procedure define-record-resumer rtype-descriptor resumer @returns{} unspecified
Sets @var{rtype-descriptor}'s record resumer to be @var{resumer}.  If
@var{resumer} is @code{#t} (the default), records of this type require
no particular reinitialization when found in @embedref{Suspending and
resuming heap images, dumped heap images}; if @var{resumer} is
@code{#f}, records of the type @var{rtype-descriptor} may not be
dumped in heap images; finally, if it is a procedure, and the heap
image is resumed with the @embedref{Suspending and resuming heap
images, usual image resumer}, it is applied to each record whose
record type descriptor is @var{rtype-descriptor} after the run-time
system has been initialized and before the argument to
@code{usual-resumer} is called.
@end deffn

@stindex records-internal
The @code{records-internal} structure also exports these:

@defvr {record type} :record-type
The record type of record types.
@end defvr

@deffn procedure disclose-record record @returns{} disclosed
This applies @var{record}'s record type descriptor's discloser procedure
to @var{record} to acquire a disclosed representation; @pxref{Writer}.
@end deffn

For expository purposes, the record type record type might have been
defined like so with Jonathan Rees's @code{define-record-type} macro:

@lisp
(define-record-type record-type :record-type
  (make-record-type name field-names)
  record-type?
  (name record-type-name)
  (field-names record-type-field-names))@end lisp

@noindent
or like so with Richard Kelsey's @code{define-record-type} macro:

@lisp
(define-record-type record-type
  (name field-names)
  ())@end lisp

@noindent
Of course, in reality, these definitions would have severe problems
with circularity of definition.

@subsection Low-level record manipulation

@cindex records, low-level access to
@cindex low-level access to records
@stindex records
Internally, records are represented very similarly to vectors, and as
such have low-level operations on them similar to vectors, exported by
the @code{records} structure.  Records usually reserve the slot at
index 0 for their record type descriptor.

@strong{Warning:} The procedures described here can be very easily
misused to horribly break abstractions.  Use them very carefully, only
in very limited & extreme circumstances!

@deffn procedure make-record length init @returns{} record
@deffnx procedure record elt @dots{} @returns{} record
@deffnx procedure record? object @returns{} boolean
@deffnx procedure record-length record @returns{} integer
@deffnx procedure record-ref record index @returns{} value
@deffnx procedure record-set! record index object @returns{} unspecified
Exact analogues of similarly named vector operation procedures.
@end deffn

@deffn procedure record-type record @returns{} value
This returns the record type descriptor of @var{record}, @ie{} the
value of the slot at index 0 in @var{record}.
@end deffn
